local Construct = {}
Construct.mt = { __index = Construct }



-- a construct is an object which has component parts
function Construct:initialize( layout, p_part_deck, origin_x, origin_y, tube_map )
	local con = {}
	setmetatable(con, Construct.mt)
	
	con.parts = {}
	con.remappers = {}	
	con.transform = MOAITransform2D.new()
	con.transform:setLoc( origin_x, origin_y )
	
	if tube_map then print("CONSTRUCT wire_map found"); con.tube_map = tube_map end
	--rawset(self, parts, {})
	--rawset(self, grid, MOAIGrid.new())
	--rawset(self, layout, layout)
	--rawset(self, layer, MOAILayer2D.new() )
	con.layer = MOAILayer2D.new()
	con.layer:setViewport( g_viewport )
	con.layer:setCamera( Game.camera )
	con.layer:setSortMode( MOAILayer2D.SORT_PRIORITY_ASCENDING )
	self.layout = layout
	print("CONSTRUCT init self.layout ")
	con.layout = layout
	con.grid = MOAIGrid.new()--Construct.re_assemble( con, layout )
	con.grid:setSize( #con.layout[1], #con.layout, TILE_SIZE, TILE_SIZE )
	con.origin_x = origin_x
	con.origin_y = origin_y
	con.height = #con.layout
	con.width = #con.layout[1]
	con.dmg_rate = BASE_DAMAGE_RATE
	
	local rt = MOAIRenderMgr.getRenderTable()
	
	Game:render_layer( con.layer )
	
	--rawset(self, parts.parent, Part:new(p_part_deck, 1, origin_x, origin_y ) )
	--self.parts.parent = Part:new(p_part_deck, 1, px, py )
	
	
	--Construct.assemble_layout(con, layout)
	con.stations = {}
	
	Construct.build(con, con.layer)
	local net_func = function(con) 
		Construct.network(con)
		Construct.make_network_map( con, WIRE_TYPE )
		Construct.make_network_map( con, WATER_PIPE_TYPE)
		Construct.make_network_map( con, WASTE_PIPE_TYPE)
		Construct.make_network_map( con, SUPPLY_PIPE_TYPE)
		Construct.make_network_map( con, OXYGEN_HOSE_TYPE)
		Construct.set_station_maps( con )
		print(" CONSTRUCT NETWORK MAPPED " )
		
	end
	
	local thread = MOAICoroutine.new()
	if con.tube_map then thread:run( net_func, con ) end
	
	
	--self:parent_parts()
	--self:re_assemble()
	
	--self:parent_parts()
	--con.col_grid = MOAIGrid.new()
	
	--con.col_grid = MapManager:collision_grid ( con.grid )
	con.dock = Construct.get_airlock(con)
	con.accept_dock = true
	con.docked = false
	con.dock_time = 5
	con.moving = false
	
	con.wires = {}
	con.wire_vis = true
	con.oxy_vis = true
	con.waste_vis = true
	con.supply_vis = true
	con.water_vis = true
	
	--con.all_props = {} deprecated
	con.all_dmgable = {}
	
	--self.id = ConstructManager:add( self )
	--rawset(self, id, ConstructManager:add( self) )
	return con
end

function Construct:update(dt)

	local x, y = self.transform:getLoc()
	self.x = x
	self.y = y
	
	--self:update_dmgable()

end

function Construct:toggleDock()

	if self.docked then self.docked = false
	else self.docked = true end

end

function Construct:get_dmgable()

	return self.all_dmgable

end

function Construct:get_dmgable_id(id)

	return self.all_dmgable[id]
end

function Construct:update_dmgable()

	for i = 1, #self.all_dmgable do
	
		local d = self.all_dmgable[i]
		
		if d.health > 0 then
			d.alive = true
		elseif d.health <= 0 then
			d.health = 0
			d.alive = false
		
		end
		
		if d.is_tube then
			
			if not d.alive then
				
				
			
			end
		
		end
		
	
	end

end

function Construct:take_damage( damage )

	if not self.damage_rate then self.damage_rate = BASE_DAMAGE_RATE end
	local dr = self.damage_rate
	local d = damage
	local d_mod = BASE_DAMAGE_MOD
	local dm = (dr - ((dr + d) / 2))/d_mod
	
	for i = 1, #self.all_dmgable do
		
		local tar = Construct.get_dmgable_id(self, i)
		
		
		local c_dmg
		if tar.health then
			if tar.health > 0 then
				if tar.dmg_rate then
					tar.health = round(tar.health - dm*tar.dmg_rate, 2)
					c_dmg = dm*tar.dmg_rate
				else
					tar.health = round(tar.health - dm, 2)
					c_dmg = dm
				end
			end
		end
		
		print("CONST TAKE_DAMAGE " .. tar.type .. " health " .. tar.health)
		
		if tar.name == "water_tubes" or
			tar.name == "waste_tubes" or
			tar.name == "supply_tubes" or
			tar.name == "wires" or
			tar.name == "air_tubes"	then
			
			local x = tar.origin_x/TILE_SIZE
			local y = tar.origin_y/TILE_SIZE
			
			print("CONT'D CONST TAKE_DAMAGE " .. 
				(tar.name or tar.type) .. 
				" at x: " .. x .. " y: " .. y ..
				" damaged for " .. c_dmg .. 
				" health is now " .. tar.health)
			local tube_typer = {
				["water_tubes"] = WATER_PIPE_TYPE,
				["waste_tubes"] = WASTE_PIPE_TYPE,
				["supply_tubes"] = SUPPLY_PIPE_TYPE,
				["wires"] = WIRE_TYPE,
				["air_tubes"] = OXYGEN_HOSE_TYPE,				
			
			}
			
			local tube_t = tube_typer[tar.name]
			
			
			if self.network_map[tube_t] then				
				
				if tar.health > 0 then
					Construct.set_net_map(self, tube_t, x, y, true)
				elseif tar.health <= 0 then
					Construct.set_net_map(self, tube_t, x, y, false)
				end
				
				local a
			end
			
			if tube_t == WIRE_TYPE then
				for i = 1, #self.stations.fc do
					local ssf = self.stations.fc[i]
					FuelCell.test_connections(ssf)
				
				end
			
			end
			
		end
	end

end

function Construct:set_net_map(type, x, y, walkable)
	if walkable then
		self.network_map[type][y][x] = WALKABLE_TILE
	else
		self.network_map[type][y][x] = UNWALKABLE_TILE		
	end

end

-- DEPRECATED SEE DMGABLE BELOW
function Construct:build_all_props()
	
	-- all parts
	for i = 1, #self.parts do
	
		local iter = #self.all_props+1
		self.all_props[iter] = self.parts[i].prop
	
	end
	
	-- all stations (hopefully)
	for key, value in pairs(self.stations) do
		
		-- rejects cat because cat is incomplete
		if key ~= "cat" then
			
			for i = 1, #self.stations[key] do
				local iter = #self.all_props+1
				self.all_props[iter] = self.stations[key][i].prop
			
			end
		
		end
	
	end

end

function Construct:build_dmgable()
-- for building dmgables we will know immediately
--based on build_all_props above ( deprecated )
	
	-- all parts
	for i = 1, #self.parts do
	
		local iter = #self.all_dmgable+1
		self.all_dmgable[iter] = self.parts[i]
	
	end
	
	-- all stations (hopefully)
	for key, value in pairs(self.stations) do
		
		-- rejects cat because cat is incomplete
		if key ~= "cat" then
			
			for i = 1, #self.stations[key] do
				local iter = #self.all_dmgable+1
				self.all_dmgable[iter] = self.stations[key][i]
			
			end
		
		end
	
	end
	
	if self.passengers then
		
		for i = 1, #self.passengers do
			
			Construct.add_dmgable(self, self.passengers[i])
		
		end
	
	end
end

function Construct:add_dmgable( dmgable )
	-- for adding dmgables we find later
	local iter = #self.all_dmgable+1
	self.all_dmgable[iter] = dmgable

end

function Construct:toggleThrusters()


end

function Construct:set_station_maps()

	for i = 1, #self.stations do
	
		local station = self.stations[i]
		
		station:make_map()
	
	end

end

function Construct:connect_electric()

	local fc = self.stations.fc
	local cat = self.stations.cat
	
	for i = #cat, 1, -1 do	
		if cat[i].type == 'fuel_cell' then		
			table.remove(cat, i)		
		end	
	end
	
	local div
	-- if more than one fuel cell
	if #fc > 1 then
		
		div = math.ceil(#cat/#fc)
		
		local offset = 0
		
		for i = 1, #fc do
			
			for j = 1, div do
				-- divide stations among fuel cells
				-- still to be tested
				if fc[i] and cat[j+offset] and j > 1 then
					fc[i]:connect( cat[j+offset] )
					offset = offset+1
				else
					fc[i]:connect( cat[j])
				end	
			
			end
		
		end
		
	else
		-- if single fuel cell, add to only fuel cell
		for i = 1, #cat do
			if fc[1] and cat[i] then
				local a
				FuelCell.connect( fc[1], cat[i] )
			end
		
		end
	
	end
	
	
	local a
	
	

end

function Construct:show_network( type )	

	local types = {
		[WIRE_TYPE] = 'wires',
		[OXYGEN_HOSE_TYPE] = 'air_tubes',
		[WATER_PIPE_TYPE] = 'water_tubes',
		[WASTE_PIPE_TYPE] = 'waste_tubes',
		[SUPPLY_PIPE_TYPE] = 'supply_tubes',
	
	}
	
	local types2 = {
		[WIRE_TYPE] = function(self) self.wire_vis = true end,
		[OXYGEN_HOSE_TYPE] = function(self) self.oxy_vis = true end,
		[WATER_PIPE_TYPE] = function(self) self.water_vis = true end,
		[WASTE_PIPE_TYPE] = function(self) self.waste_vis = true end,
		[SUPPLY_PIPE_TYPE] = function(self) self.supply_vis = true end,
	
	}
	
	local t = types[type]
	
	if not t then print("ERROR:CONSTRUCT show_network type not valid"); return nil end
	
	types2[type](self)
	
	for i = 1, #self.wires do	
		if self.wires[i].name == t then
			self.wires[i].prop:setVisible(true)
		end
		
	end

end

function Construct:hide_network( type )	

	local types = {
		[WIRE_TYPE] = 'wires',
		[OXYGEN_HOSE_TYPE] = 'air_tubes',
		[WATER_PIPE_TYPE] = 'water_tubes',
		[WASTE_PIPE_TYPE] = 'waste_tubes',
		[SUPPLY_PIPE_TYPE] = 'supply_tubes',
	
	}
	
	local types2 = {
		[WIRE_TYPE] = function(self) self.wire_vis = false end,
		[OXYGEN_HOSE_TYPE] = function(self) self.oxy_vis = false end,
		[WATER_PIPE_TYPE] = function(self) self.water_vis = false end,
		[WASTE_PIPE_TYPE] = function(self) self.waste_vis = false end,
		[SUPPLY_PIPE_TYPE] = function(self) self.supply_vis = false end,
	
	}
	
	local t = types[type]
	
	
	if not t then print("ERROR:CONSTRUCT show_network type not valid"); return nil end
	
	types2[type](self)	
	
	for i = 1, #self.wires do	
		if self.wires[i].name == t then
			self.wires[i].prop:setVisible(false)
		end
		
	end

end

function Construct:isNetworkVisible( type )

	local types = {
		[WIRE_TYPE] = function(self) return self.wire_vis end,
		[OXYGEN_HOSE_TYPE] = function(self) return self.oxy_vis end,
		[WATER_PIPE_TYPE] = function(self) return self.water_vis end,
		[WASTE_PIPE_TYPE] = function(self) return self.waste_vis end,
		[SUPPLY_PIPE_TYPE] = function(self) return self.supply_vis end,
	
	}
	
	return types[type](self)


end

function Construct:toggle_network_vis( type ) 

	if self:isNetworkVisible( type ) then
		self:hide_network( type )
	else
		self:show_network( type )
	end

end

function Construct:make_network_map( type )
	if not self.network_map then self.network_map = {} end
	if not self.network_map[type] then self.network_map[type] = {} end
	
	
	
	for y = 1, self.height do
		self.network_map[type][y] = {}
		for x = 1, self.width do
			
			self.network_map[type][y][x] = 1
		
		end
	
	end
	
	for i = 1, #self.tube_map do
		if self.tube_map[i].type == type then
			
			self.network_map[type][self.tube_map[i].y][self.tube_map[i].x] = 0
		--else
			--self.network_map[type][self.tube_map[i].y][self.tube_map[i].x] = 1
			
		end
	
	end
	
	if type == WIRE_TYPE then
		
		for i = 1, #self.stations.cp do
			local cpx = self.stations.cp[i].x/TILE_SIZE
			local cpy = self.stations.cp[i].y/TILE_SIZE
		
			self.network_map[type][cpy][cpx] = 0
		end
		
		for i = 1, #self.stations.fc do
			local fcx = self.stations.fc[i].x/TILE_SIZE
			local fcy = self.stations.fc[i].y/TILE_SIZE
		
		
			self.network_map[type][fcy][fcx] = 0
		
		end
		
		for i = 1, #self.stations.rc do
			local otx = self.stations.rc[i].x/TILE_SIZE
			local oty = self.stations.rc[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.ot do
			local otx = self.stations.ot[i].x/TILE_SIZE
			local oty = self.stations.ot[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.wt do
			local otx = self.stations.wt[i].x/TILE_SIZE
			local oty = self.stations.wt[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.sl do
			local otx = self.stations.sl[i].x/TILE_SIZE
			local oty = self.stations.sl[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		
		
	elseif type == OXYGEN_HOSE_TYPE then
	
		for i = 1, #self.stations.ot do
			local otx = self.stations.ot[i].x/TILE_SIZE
			local oty = self.stations.ot[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
	elseif type == WATER_PIPE_TYPE then
	
		for i = 1, #self.stations.wt do
			local otx = self.stations.wt[i].x/TILE_SIZE
			local oty = self.stations.wt[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.st do
			local otx = self.stations.st[i].x/TILE_SIZE
			local oty = self.stations.st[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.fs do
			local otx = self.stations.fs[i].x/TILE_SIZE
			local oty = self.stations.fs[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
	elseif type == WASTE_PIPE_TYPE then
	
		for i = 1, #self.stations.rc do
			local otx = self.stations.rc[i].x/TILE_SIZE
			local oty = self.stations.rc[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.st do
			local otx = self.stations.st[i].x/TILE_SIZE
			local oty = self.stations.st[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
	elseif type == SUPPLY_PIPE_TYPE then
	
		for i = 1, #self.stations.fs do
			local otx = self.stations.fs[i].x/TILE_SIZE
			local oty = self.stations.fs[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.rc do
			local otx = self.stations.rc[i].x/TILE_SIZE
			local oty = self.stations.rc[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
		
		for i = 1, #self.stations.wt do
			local otx = self.stations.wt[i].x/TILE_SIZE
			local oty = self.stations.wt[i].y/TILE_SIZE
			
			self.network_map[type][oty][otx] = 0
		end
	
	end
	
	local a
end

function Construct:setLoc( x, y )

	--local thread = ThreadManager.nt()

	--thread:run(self.transform.setLoc, self, x, y)
	self.transform:setLoc( x, y )
	
	--coroutine.yield()
end

function Construct:setRot( rot )

	 self.transform:setRot( rot )
	

end

function Construct:setPiv( x, y )

	self.transform:setPiv(x, y)

end

function Construct:seekLoc( x, y, time, mode )
	
	--for i = 1, #self.parts do
	
	--local thread = ThreadManager.nt()
	
	--id = self.id
	
	--thread:run(ConstructManager.constructs[id].seekLoc, ConstructManager.constructs[id].transform, x, y, time, mode)
	local thread = MOAICoroutine.new()
	
	local t_func = function(self, x, y, time, mode)
		
		self.transform:seekLoc(x, y, time, mode)
	
	end
	
	thread:run(t_func, self, x, y, time, mode)
	
	
	--end
	--coroutine.yield()
end

function Construct:seekRot( rot, length, mode )

	local thread = MOAICoroutine.new()
	
	local t_func = function(self, rot, length, mode)
		
		self.transform:seekRot( rot, length, mode )
	
	end
	
	thread:run(t_func, self, rot, length, mode )

	
	
	--coroutine.yield()

end

function Construct:moveLoc( x, y, length, mode)

	local thread = MOAICoroutine.new()
	
	local t_func = function(self, x, y, length, mode)
	
		self.transform:moveLoc(x, y, length, mode)
	
	end
	
	thread:run(t_func, self, x, y, length, mode)
	
end

function Construct:moveRot( rot, length, mode )

	local thread = MOAICoroutine.new()
	
	local t_func = function(self, x, y, length, mode)
	
		self.transform:moveRot(rot, length, mode)
		
	
	end
	
	thread:run(t_func, self, x, y, length, mode)

	

end




function Construct.new( layout, p_part_deck, origin_x, origin_y, wire_map )

	local o = Construct:initialize( layout, p_part_deck, origin_x, origin_y, wire_map )

	return o

end

function Construct:remove()

	ConstructManager:remove( self.id )
	self = nil

end

function Construct:remove_wire( wire_id )
	table.remove(self.wires, wire_id)

end




function Construct:assemble_layout( layout )
	
	
	
	if layout then self.layout = layout end
	
	self.h = #self.layout
	self.w = #self.layout[1]
	
	
	
	for y = 1, self.h do
		--self.w = #self.layout[y]
		for x = 1, self.w do
			--prop2 = self:get_last_prop()
			-- if the tile doesn't exist make it 0, otherwise set the grid to
			-- the tile at [y][x]
			if not self.layout[y][x] then self.grid:setTile(x,y,0) else
				self.grid:setTile(x, y, self.layout[y][x])
			end		
		end	
	end
	
	
	
	--self:parent_parts()

end

function Construct:build( layer )
	
	local cp_x, cp_y = self:find_control_panel(self.layout)
	
	local init_col_grid
	
	if not self.h then self.h = #self.layout end
	if not self.w then self.w = #self.layout[1] end
	
	local transform = self:get_transform()
	
	local tx, ty = transform:getLoc()
	self.x = tx
	self.y = ty
	
	for y = 1, self.h do
		for x = 1, self.w do
	
	
	
			local iter = #self.parts+1
			local d = Game:resource_from_number(self.layout[y][x])
			local iter2 = #self.parts+2
			--print(d)
			
			
				
			local x1 = (x)*(TILE_SIZE)
			local y1 = (y)*(TILE_SIZE)
			
			
			local grid = self:get_grid()
			if self.layout[y][x] then
				grid:setTile(x, y, self.layout[y][x])
			else
				grid:setTile(x, y, 0)
			end
			
			--print(d)
			if d ~= 'blank' then				
				--rawset(self.parts, iter, Part:new(d, iter, x1, y1, parent_package)	)			
				if Game:isWorkstation(self.layout[y][x]) then
					local d = Game:resource_from_number(FLOOR_TILE)
					self.parts[iter2] = Part.new(d, iter2, x1, y1, transform, layer)
					self:insertProp( self.parts[iter2].prop )
					self.parts[iter] = WorkStation.place(self.layout[y][x], x*TILE_SIZE, y*TILE_SIZE, self)
					self:place_station(x, y, iter) 
				else
				
					self.parts[iter] = Part.new(d, iter, x1, y1, transform, layer)		
					if d == HOOK_NAME then --print("found hook"); 
						print("CONSTRUCT build hook found")
						self:mark_hook(self.parts[iter]) end
					if d == AIRLOCK_NAME then --print("found airlock"); 
						print("CONSTRUCT build airlock found")
						self:mark_airlock(self.parts[iter]) end
					if d == THRUSTER_NAME then
						print("CONSTRUCT build thruster found")
						self:mark_thruster(self.parts[iter]) end
					--print(x1, y1)
					--local p_rop = rawget(self.parts[iter], prop)
					if d ~= HOOK_NAME then self:insertProp( self.parts[iter].prop )	end
					
					self.parts[iter].x = x1
					self.parts[iter].y = y1
				
				end
				
			
			end
			
			if not init_col_grid then init_col_grid = {} end
			if not init_col_grid[y] then init_col_grid[y] = {} end
			
			if MapManager:isWalkable(self.layout[y][x]) then				
				
				init_col_grid[y][x] = 0
				
				--print("CONSTRUCT build walkable at x ".. x .. " y " .. y)
				
			else
			
				init_col_grid[y][x] = 1
				
			
			end
			
			
		end
	end
	
	self.col_grid = jGrid(init_col_grid)
			


end

function Construct:make_floor(x, y)


end

function Construct:mark_thruster( thruster )
	if not self.parts.thrusters then self.parts.thrusters = {} end
	
	local iter = #self.parts.thrusters+1
	
	print("CONSTRUCT mark_thruster")
	
	self.parts.thrusters[iter] = thruster


end

function Construct:mark_hook( hook )

	if not self.parts.hooks then self.parts.hooks = {} end
	
	local iter = #self.parts.hooks+1
	
	self.parts.hooks[iter] = hook

end

function Construct:mark_airlock( airlock )
	if not self.parts.airlock then self.parts.airlock = {} end
	
	local iter = #self.parts.airlock+1
	
	self.parts.airlock[iter] = airlock

end

function Construct:re_assemble( lay )

	layout = lay or self.layout
	
	local grid = MOAIGrid.new()
	
	for y = 1, #layout do
		for x = 1, #layout[y] do
		
			grid:setTile(x, y, layout[y][x])	
		
		end
	end
	
	return grid

end

function Construct:insertProp( prop )

	self.layer:insertProp( prop )

end

function Construct:parent_parts()

	local prop = self:get_main_prop()
	local parts = self:get_parts()

	for k, v in pairs(parts) do
	
		
		--print("not parent")
		v:setParent(prop, 'tvc' )
		--[[
		local x = rawget(v, origin_x)
		local y = rawget(v, origin_y)
		--print("v at ".. x .. " " .. y )
		v:setLoc(x, y)
		]]
		
	
	end


end

function Construct:parent_parts_t()

	local transform = self:get_transform()
	local parts = self:get_parts()
	for i = 1, #parts do
		print("CONSTRUCT adding parent")
		parts[i]:setParent(transform, 't')
		--parts[i].prop:setAttrLink( MOAIProp2D.INHERIT_TRANSFORM, transform, MOAITransform2D.TRANSFORM_TRAIT)
		--parts[i].prop:setAttrLink( MOAIProp2D.INHERIT_LOC, transform, MOAITransform2D.TRANSFORM_TRAIT)
		--parts[i].prop:forceUpdate()
		--transform:forceUpdate()
	
	end

end



function Construct:check_links()



end

--[[
function Construct:get_last_part()
	
	
	return self.parts[#self.parts]


end

]]
function Construct:print_parts()

	local x, y 

	for i = 1, #self.parts do
	
		x, y = self.parts[i]:getLoc()
		print("CONSTRUCT print_parts " .. x .. ' ' .. y)
	
	end

end

function Construct:get_layer()

	return self.layer

end

function Construct:get_wires()

	return self.wires

end

function Construct:get_grid()

	return self.grid

end

function Construct:get_hooks()

	return self.parts.hooks, #self.parts.hooks
end

function Construct:get_parts()

	return self.parts

end



function Construct:get_transform()

	return self.transform

end

function Construct:get_main_prop()
	
	return self.transform

end

function Construct:find_control_panel( layout )

	local layout_x, layout_y, parts_iter
	
	if not layout then layout = self.layout end
	
	for y = 1, #layout do
		for x = 1, #layout[y] do
			--print(layout[y][x])
			if layout[y][x] == CONTROL_PANEL then
				
				layout_x = x
				layout_y = y
			
			end
		
		end
	
	end
	if layout_x and layout_y then
		--print("control panel at " .. layout_x .. " " .. layout_y)
	end
	
	return layout_x, layout_y

end

function Construct:find_feature( feature, layout  )
	
	local layout_x, layout_y, parts_iter
	
	if not layout then layout = self.layout end
	
	local features = {}
	
	local ftcount = 1
	
	for y = 1, #layout do
		for x = 1, #layout[y] do
			if layout[y][x] == feature then				
				if not features[ftcount] then features[ftcount] = {} end
				features[ftcount].x = x
				features[ftcount].y = y
				
				ftcount = ftcount+1
			
			
			end
		
		
		
		end
	
	
	end
	
	return features

end

function Construct:place_control_panel()
	
	local x, y = self:find_control_panel()
	
	local iter = #self.stations+1
	
	self.stations.cp = ControlPanel.new( x, y )

end

function Construct:place_fuel_cells()

	local cells = self:find_feature(FUEL_CELL)
	
	local iter 
	
	for i = 1, #cells do	
	
		if self.stations.fc then iter = #self.stations.fc+1
		else self.stations.fc = {}; iter = #self.stations.fc+1 end
	
		self.stations.fc[iter] = FuelCell.new( cells[i].x, cells[i].y )
	
	
	end
	
	


end

function Construct:place_station(x, y, iter1)

	--self:place_control_panel()
	--self:place_fuel_cells()
	
	local stations = {
		FOOD_STATION,
		WATER_TANKS,
		OXYGEN_TANKS,
		RECYCLER,
		SPACE_TOILET,
		CONTROL_PANEL,
		FUEL_CELL,
		SLEEP_TUBE
	
	}
	
	local stat = self.parts[iter1]
	local num_type = self.layout[y][x]
	
		
	local suffix = self:station_num_to_suffix( num_type )
	print("CONSTRUCT suffix = " .. suffix)
	local iter
	print("CONSTRUCT placing station")	
	--if not self.stations then self.stations = {} end
	if self.stations[suffix] then iter = #self.stations[suffix]+1
	else self.stations[suffix] = {}; iter = #self.stations[suffix]+1 end
	print("CONSTRUCT iter = " .. iter)
			
	self.stations[suffix][iter] = stat
	
	if not self.stations.cat then self.stations.cat = {} end
	local iter2 = #self.stations.cat+1
	self.stations.cat[iter2] = stat

end


function Construct:station_num_to_suffix( num )

	local stations = {
		[CONTROL_PANEL] = 'cp',
		[FUEL_CELL] = 'fc',
		[FOOD_STATION] = 'fs',
		[WATER_TANKS] = 'wt',
		[OXYGEN_TANKS] = 'ot',
		[SPACE_TOILET] = 'st',
		[RECYCLER] = 'rc',
		[SLEEP_TUBE] = 'sl',
	
	}
	
	return stations[num]

end

function Construct:network()


	if self.tube_map then
	
		for i = 1, #self.tube_map do
		
			local tube_types = {
				[WIRE_TYPE] = function( self )
					local wire = Wire.new(self.tube_map[i].dir, 
						self.tube_map[i].x*TILE_SIZE, self.tube_map[i].y*TILE_SIZE, 
						self.transform, self.layer)
					print("CABLE wire added")				
					
					return wire
				end,
				[OXYGEN_HOSE_TYPE] = function( self )
					local oxy = OxygenHose.new(self.tube_map[i].dir, 
						self.tube_map[i].x*TILE_SIZE, self.tube_map[i].y*TILE_SIZE, 
						self.transform, self.layer)
						print("ATMOSPHERE oxygen hose added")
						
					return oxy
				
				
				end,
				
				[WATER_PIPE_TYPE] = function( self )
					local wp = WaterPipe.new(self.tube_map[i].dir, 
						self.tube_map[i].x*TILE_SIZE, self.tube_map[i].y*TILE_SIZE, 
						self.transform, self.layer)
					print("PLUMBING water pipe added")				
					
					return wp
				end,
				
				[WASTE_PIPE_TYPE] = function( self )
					local wp = WastePipe.new(self.tube_map[i].dir, 
						self.tube_map[i].x*TILE_SIZE, self.tube_map[i].y*TILE_SIZE, 
						self.transform, self.layer)
					print("SEWAGE waste pipe added")				
					
					return wp
				end,
				
				[SUPPLY_PIPE_TYPE] = function( self )
					local sp = SupplyPipe.new(self.tube_map[i].dir, 
						self.tube_map[i].x*TILE_SIZE, self.tube_map[i].y*TILE_SIZE, 
						self.transform, self.layer)
					print("CABLE wire added")
					
					return sp
				end,
			
			
			}
			local iter = #self.wires +1
			self.wires[iter] = tube_types[self.tube_map[i].type](self)
			local swi = self.wires[iter]
			
			Construct.add_dmgable(self, swi)
		
		end	
	end
	--local a
end



function Construct:add_wire(wire)

	local iter = #self.wires+1
	self.wires[iter] = wire
	
	return iter


end

function Construct:get_airlock()
--[[
	local parts = self:get_parts()
	print("#parts " .. #parts)
	for i = 1, #parts do
		--print(i..parts[i].name)
		if parts[i].name == AIRLOCK_NAME then
			print("found airlock")
			return parts[i]
		
		end
	end
	
	]]
	local a = self.parts.airlock
	
	
	return a


end

function Construct:docks( cons )
	
	print("CONSTRUCT docks cons.id " .. cons.id)
	local d1 = self:get_dock()
	local d2 = cons:get_dock()
	
	if not d1 or not d2 then
		print("CONSTRUCT docks breaking")
		
		return nil
	
	end

	if d2.docking == false then
		if d2.accept_dock == true then
			print("CONSTRUCT beginning docking")
			
			d2.docking = true
			
			local r = d2.transform:getRot()
			if r == 0 then r = 180 end
			print("CONSTRUCT dock d2 rot : " .. r )		
			
			d1:seekRot_w(180-(360-r), d1.dock_time) 
			--d1:seekRot_w(180, d1.dock_time)
			--d2:seekRot_w(0, d2.dock_time)
			
			
			local air1 = d1.get_airlock(d1)
			local air2 = d2.get_airlock(d2)
			
			local ax1, ay1 = air1:modelToWorld()
			local ax2, ay2 = air2:modelToWorld()
			
			--local ax1, ay1 = air1.prop:getLoc()
			--local ax2, ay2 = air2.prop.getLoc(air2.prop)
			
			local cx1, cy1 = d1.transform:getLoc()
			local cx2, cy2 = d2.transform:getLoc()
			
			print( "CONSTRUCT dock axis " .. ax1, ay1, ax2, ay2, cx1, cy1, cx2, cy2)
			
			local dx = cx1 - ax1
			local dy = cy1 - ay1
			local dx2 = cx2 - ax2
			local dy2 = cy2 - ay2
			
			offsetX = math.ceil((d2.w*0.5)*TILE_SIZE)
			
			print("CONSTRUCT dock dxs " .. dx, dy, dx2, dy2)
			
			d1:moveLoc(ax2-offsetX+TILE_SIZE*0.5, ay2-TILE_SIZE*2-TILE_SIZE*0.25, d1.dock_time)
			--[[
			local dx = cx2 - cx1
			local dy = cy2 - cy1
			local dx2 = ax2 - ax1
			local dy2 = ay2 - ay1
			
			dx2 = dx2+d1.w
			dy2 = dy2+d1.h
			dx = dx+dx*0.5
			dy = dy+dy*0.5
			
			d1:moveLoc_w(dx, dy, d1.dock_time)
			d2:moveLoc_w(-dx, -dy, d2.dock_time)
			
			air1 = d1.get_airlock(d1)
			air2 = d2.get_airlock(d2)
			
			ax1, ay1 = air1.prop:modelToWorld()
			ax2, ay2 = air2.prop.modelToWorld(air2.prop, air2.prop:getLoc())
			
			cx1, cy1 = d1.transform:getLoc()
			cx2, cy2 = d2.transform:getLoc()
			
			print(ax1, ay1, ax2, ay2, cx1, cy1, cx2, cy2)
			
			dx = cx2 - cx1
			dy = cy2 - cy1
			dx2 = ax2 - ax1
			dy2 = ay2 - ay1
			
			d1:moveLoc(dx, dy, d1.dock_time)
			
			]]
			
			
	
		end
	end
	


end

function Construct:get_dock()
	local d = ConstructManager.constructs[self.id]
	return d

end



return Construct